1. Setup Environment
require(ggplot2)
require(summarytools)
require(cowplot)
require(caret)
require(corrplot)
require(RColorBrewer)
require(vembedr)
require(Rmisc)
require(varian)
package ‘rstan’ was built under R version 4.0.2Failed with error: ‘package ‘rstan’ could not be loaded’
require(patchwork)
require(plotly)
require(Metrics)
require(dplyr)
require(ggpubr)
require(mosaic)
require(openxlsx)
require(visreg)
require(factoextra)
require(rstatix)
require(gridExtra)
require(colorspace)
require(grid)
require(data.table)
require(psych)
source('~/Documents/GitHub/SmartphoneSensorPipeline/Extra/plotting_functions.R')
project_path = "~/Documents/xia_gps/"
data_path = file.path(project_path,"beiwe_output_043020")
gps_df_path = file.path(data_path,"Processed_Data/Group/feature_matrix.txt")
2.Prepare GPS data
gps_df = read.table(gps_df_path,header = T, dec = ",")[,c(1,2,97:111)]
gps_df[,3:17] = apply(gps_df[,3:17],2,as.numeric)
# loop through each subj to remove 1st and last days of gps data
gps_df_clean = data.frame() #initiate a df
for (subj in unique(gps_df$IID)){ #loop through each subj
gps_df_subj <- subset(gps_df, IID == subj) #get gps_df per subject
gps_df_subj <- gps_df_subj[2:(dim(gps_df_subj)[1]-1),] #remove the 1st and last days
gps_df_clean <- rbind(gps_df_clean,gps_df_subj) #combine all subjs
}
# exclude days with too much excessiveness
sensitivity_cutoff = 1440 # this controls the cutoff threshold
gps_df_clean2 = subset(gps_df_clean, MinsMissing < sensitivity_cutoff)
set.seed(510)
make_subj_seq = function(gps_df_clean2,part_times) {
subj_seq = list()
for (subj in unique(gps_df_clean2$IID)){
subj_data = subset(gps_df_clean2, IID==subj)
if (dim(subj_data)[1] >5) {
subj_seq[[subj]] <-createDataPartition(subj_data$IID,times = part_times, p =0.5)
}
}
return(subj_seq)
}
part_times = 1000
subj_seq = make_subj_seq(gps_df_clean2, part_times)
# an example of subj 1, and first half
example_data = gps_df_clean2[subj_seq$`16xv6ko1`$Resample0001,3:17]
gps_cor = rquery.cormat(example_data, type = "full")

gps_clean2_feature = make_feature_matrix(gps_df_clean2, subj_seq, 3:17 )
subject_seq = names(gps_clean2_feature$subj_mat_1)
gps_wide_matrix = data.frame()
subj_days = gps_df_clean2 %>% group_by(IID) %>% dplyr::tally(name = "Days Collected")
for (subj in arrange(subj_days,`Days Collected`)$IID){
#if ((subj %in% subj_days$IID[which(subj_days$`Days Collected`<=10)]) == T) {
for (part in 1:5){
half_1 = gps_clean2_feature$subj_mat_1[[subj]][[part]]$cor
half_2 = gps_clean2_feature$subj_mat_2[[subj]][[part]]$cor
half_1_half_2 = c(half_1,half_2)
gps_wide_matrix = rbind(gps_wide_matrix,half_1)
gps_wide_matrix = rbind(gps_wide_matrix,half_2)
}
#}
}
gps_wide_matrix = t(gps_wide_matrix)
gps_corplot = rquery.cormat(gps_wide_matrix, type = "full",graph=FALSE)
gps_corplot$subj = arrange(subj_days,`Days Collected`)$IID
levelplot(gps_corplot$r,scales=list(draw=FALSE),col.regions = rev(rainbow(1000))[-c(1:20)], region =T, ylab.right = "Pearson correlation", main=list(label='GPS Feature Similarity'),xlab="",ylab="")

3. Prepare accelerometer data
subj_list = unique(gps_df$IID)
subj_acc_data_dim = dim(rbindlist(lapply(subj_list, function(subj) {subj_data = readRDS(file.path(data_path,"Results/Group/accelerometer",subj,"accelerometer_ft.rds")); subj_data[,c(2:8,11)]})))
subj_acc_data_clean = as.data.frame(rbindlist(lapply(subj_list, function(subj) { subj_data = readRDS(file.path(data_path,"Results/Group/accelerometer",subj,"accelerometer_ft.rds")); subj_data[2:(dim(subj_data)[1]-1),c(2:8,11)]}))) #also removes 1st and last day
example_acc_data = subj_acc_data_clean[subj_seq$`16xv6ko1`$Resample0001,1:7]
Warning messages:
1: In readChar(file, size, TRUE) : truncating string with embedded nuls
2: In readChar(file, size, TRUE) : truncating string with embedded nuls
acc_cor = rquery.cormat(example_acc_data, type = "full")

subj_acc_data_clean$IID = subj_acc_data_clean$subject
set.seed(510)
acc_subj_seq = make_subj_seq(subj_acc_data_clean, part_times)
acc_clean_feature = make_feature_matrix(subj_acc_data_clean, acc_subj_seq, c(1:7) )
acc_wide_matrix = data.frame()
subj_acc_days = subj_acc_data_clean %>% group_by(IID) %>% dplyr::tally(name = "acc_days")
for (subj in arrange(subj_acc_days,`acc_days`)$IID){
for (part in 1:5){
half_1 = acc_clean_feature$subj_mat_1[[subj]][[part]]$cor
half_2 = acc_clean_feature$subj_mat_2[[subj]][[part]]$cor
half_1_half_2 = c(half_1,half_2)
acc_wide_matrix = rbind(acc_wide_matrix,half_1)
acc_wide_matrix = rbind(acc_wide_matrix,half_2)
}
}
acc_wide_matrix = t(acc_wide_matrix)
acc_corplot = rquery.cormat(acc_wide_matrix, type = "full",graph=FALSE)
acc_corplot$subj = arrange(subj_acc_days,`acc_days`)$IID
levelplot(acc_corplot$r,scales=list(draw=FALSE),col.regions = rev(rainbow(1000))[-c(1:20)], region =T, ylab.right = "Pearson correlation", main=list(label='Acc Feature Similarity'),xlab="",ylab="")

4. Merge GPS and accelerometer data
gps_acc_combined_feat = list()
for (subj in subj_list){
for (time in 1:part_times){
gps_feat1 = gps_clean2_feature$subj_mat_1[[subj]][[time]]$cor
acc_feat1 = acc_clean_feature$subj_mat_1[[subj]][[time]]$cor
gps_feat2 = gps_clean2_feature$subj_mat_2[[subj]][[time]]$cor
acc_feat2 = acc_clean_feature$subj_mat_2[[subj]][[time]]$cor
gps_acc_combined_feat$subj_mat_1[[subj]][[time]] = c(gps_feat1, acc_feat1)
gps_acc_combined_feat$subj_mat_2[[subj]][[time]] = c(gps_feat2, acc_feat2)
}
}
5. GPS and accelerometer based Individual Identification
match_combined_gps_accfeat = calc_match_vector(gps_acc_combined_feat$subj_mat_1, gps_acc_combined_feat$subj_mat_2, "cor")
acc_time_cb_accgps = calc_acc_time(match_combined_gps_accfeat, "max")
acc_subj_cb_accgps = calc_acc_subj(match_combined_gps_accfeat, "max")
p = hist_chx(acc_time_cb_accgps, bins = 14, title = paste("Individual Identificaiton Accuracy \n (GPS+ Accel)"), xaxis = "Prediction Accuracy", yaxis = "Count")
ggplotly(p)
perm_time = 10
gps_df_perm = gps_df_clean2
acc_df_perm = subj_acc_data_clean
perm_acc_gps_time = list()
perm_acc_gps_subj = list()
for (i in 1:perm_time) {
perm_part_times = 1
print(paste("processing ...", i,"..."))
gps_df_perm$IID = sample(gps_df_perm$IID)
acc_df_perm$IID = sample(acc_df_perm$IID)
perm_subj_seq = make_subj_seq(gps_df_perm,part_times = perm_part_times)
perm_acc_subj_seq = make_subj_seq(acc_df_perm,part_times = perm_part_times)
perm_gps_cor = make_feature_matrix(gps_df_perm,perm_subj_seq,3:17)
perm_acc_cor = make_feature_matrix(acc_df_perm,perm_acc_subj_seq,1:7)
subj_mat_1 = list()
subj_mat_2 = list()
for (subj in subj_list){
subj_mat_1[[subj]]$Resample1 = as.numeric(c(perm_gps_cor$subj_mat_1[[subj]][[1]]$cor, perm_acc_cor$subj_mat_1[[subj]][[1]]$cor))
subj_mat_2[[subj]]$Resample1 = as.numeric(c(perm_gps_cor$subj_mat_2[[subj]][[1]]$cor, perm_acc_cor$subj_mat_2[[subj]][[1]]$cor))
}
perm_gps_acc_mats = list(subj_mat_1 = subj_mat_1, subj_mat_2 = subj_mat_2)
perm_match = calc_match_vector(perm_gps_acc_mats$subj_mat_1,perm_gps_acc_mats$subj_mat_2, "cor")
perm_acc_gps_time[[i]] = calc_acc_time(perm_match, "max")
perm_acc_gps_subj[[i]] = calc_acc_subj(perm_match, "max")
}
perm_acc_gps_time = unlist(perm_acc_gps_time)
perm_acc_gps_subj = unlist(perm_acc_gps_subj)
df = data.frame(val = perm_acc_gps_time)
Warning messages:
1: In readChar(file, size, TRUE) : truncating string with embedded nuls
2: In readChar(file, size, TRUE) : truncating string with embedded nuls
3: In readChar(file, size, TRUE) : truncating string with embedded nuls
4: In readChar(file, size, TRUE) : truncating string with embedded nuls
5: In readChar(file, size, TRUE) : truncating string with embedded nuls
6: In readChar(file, size, TRUE) : truncating string with embedded nuls
p = ggplot(df, aes(x=val)) +
geom_histogram(bins = 7, fill = "#9ECAE1", size = 2) +
theme_cowplot() +
labs(title=paste("GPS+Accel: \n",part_times,"Permutations"),
x = "Individual Identificaiton Accuracy", y = "Count") +
#geom_density(alpha=.2) +
theme(plot.title = element_text(hjust = 0.5))
ggplotly(p)
perm_subj = sapply(subject_seq, function(subj) sum(perm_acc_gps_subj[which(names(perm_acc_gps_subj) == subj)])/1000)
Warning messages:
1: In readChar(file, size, TRUE) : truncating string with embedded nuls
2: In readChar(file, size, TRUE) : truncating string with embedded nuls
3: In readChar(file, size, TRUE) : truncating string with embedded nuls
4: In readChar(file, size, TRUE) : truncating string with embedded nuls
5: In readChar(file, size, TRUE) : truncating string with embedded nuls
6: In readChar(file, size, TRUE) : truncating string with embedded nuls
subj_df <- data.frame(x=names(subj_seq))
subj_df$y = acc_subj_cb_accgps
subj_df$y_perm = perm_subj
subj_df = subj_df[order(subj_df$y),]
p_subj_cor_perm = ggplot(subj_df, aes(x = reorder(x, y), y = value)) +
geom_point(aes(y = y), color = "#F69274", size = 2) +
geom_point(aes(y = y_perm), color = "#9ECAE1", size =2 ) +
theme_cowplot() +
labs(title = paste("GPS+Accel \n Subject Level Accuracy Across",part_times,"Data Partitions"),
x = "Subjects", y = "Individual Identification Accuracy") +
theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 8), plot.title = element_text(hjust = 0.5))
ggplotly(p_subj_cor_perm)
6. GPS only based Individual Identification
gps_match_cor = calc_match_cor(gps_clean2_feature$subj_mat_1,gps_clean2_feature$subj_mat_2)
gps_acc_time = calc_acc_time(gps_match_cor, "max")
gps_acc_subj = calc_acc_subj(gps_match_cor)
gps_df_perm = gps_df_clean2
perm_time = 1000
perm_acc_time = list()
perm_acc_subj = list()
for (i in 1:perm_time) {
perm_part_times = 1
print(paste("processing ...", i,"..."))
gps_df_perm$IID = sample(gps_df_perm$IID)
perm_subj_seq = make_subj_seq(gps_df_perm, part_times = perm_part_times)
perm_gps = make_feature_matrix(gps_df_perm,perm_subj_seq,3:17)
perm_mat_1 = perm_gps$subj_mat_1
perm_mat_2 = perm_gps$subj_mat_2
perm_match_cor = calc_match_cor(perm_mat_1,perm_mat_2)
perm_acc_time[[i]] = calc_acc_time(perm_match_cor)
perm_acc_subj[[i]] = calc_acc_subj(perm_match_cor)
}
p_time_cor = hist_chx(acc_time, bins = 17, title = paste("GPS: \n Individual identification accuracy"), xaxis = "Individual identification accuracy", yaxis = "Count")
ggplotly(p_time_cor)
#perm_acc_time_all = unlist(perm_acc_time)
Warning messages:
1: In readChar(file, size, TRUE) : truncating string with embedded nuls
2: In readChar(file, size, TRUE) : truncating string with embedded nuls
q_time_cor = hist_chx(perm_acc_time_all, bins = 7, title = paste("GPS accuracy across",length(perm_acc_time_all),"Permutations"), xaxis = "Individual Identificaiton Accuracy", yaxis = "Count")
ggplotly(q_time_cor)
perm_acc_subj = unlist(perm_acc_subj)
perm_subj = sapply(subject_seq, function(subj) sum(perm_acc_subj[which(names(perm_acc_subj) == subj)])/1000)
subj_df <- data.frame(x=names(subj_seq))
subj_df$y = gps_acc_subj
subj_df$y_perm = perm_subj
subj_df = subj_df[order(subj_df$y),]
p_subj_cor_perm = ggplot(subj_df, aes(x = reorder(x, y), y = value)) +
geom_point(aes(y = y, col = "subject data")) +
geom_point(aes(y = y_perm, col = "permutation")) +
theme_cowplot() +
labs(title = paste("GPS \n Subject Level Accuracy Across",perm_time,"permutations"),
x = "Subjects", y = "Individual identification accuracy") +
theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 8), plot.title = element_text(hjust = 0.5))
ggplotly(p_subj_cor_perm)
7. Accelerometer only based Individual Identification
acc_match_cor = calc_match_cor(acc_clean_feature$subj_mat_1,acc_clean_feature$subj_mat_2)
acc_acc_time = calc_acc_time(acc_match_cor, "max")
acc_acc_subj = calc_acc_subj(acc_match_cor)
acc_df_perm = subj_acc_data_clean
perm_time = 1000
perm_acc_acc_time = list()
perm_acc_acc_subj = list()
for (i in 1:perm_time) {
perm_part_times = 1
print(paste("processing ...", i,"..."))
acc_df_perm$IID = sample(acc_df_perm$IID)
perm_subj_seq = make_subj_seq(acc_df_perm, part_times = perm_part_times)
perm_acc = make_feature_matrix(acc_df_perm,perm_subj_seq,1:7)
perm_mat_1 = perm_acc$subj_mat_1
perm_mat_2 = perm_acc$subj_mat_2
perm_match_cor = calc_match_cor(perm_mat_1,perm_mat_2)
perm_acc_acc_time[[i]] = calc_acc_time(perm_match_cor)
perm_acc_acc_subj[[i]] = calc_acc_subj(perm_match_cor)
}
df = data.frame(val = acc_acc_time)
p = ggplot(df, aes(x=val)) +
geom_histogram(bins = 15, fill = "#F69274", size = 2) +
theme_cowplot() +
labs(title=paste("Accelerometer Features: \n Average Accuracy Across",part_times,"Data Partitions"),
x = "Mobility Footprint Individual Identification Accuracy", y = "Count") +
#geom_density(alpha=.2) +
theme(plot.title = element_text(hjust = 0.5))
ggplotly(p)
df = data.frame(val = perm_acc_acc_time)
p = ggplot(df, aes(x=val)) +
geom_histogram(bins = 5, fill = "#9ECAE1", size = 2) +
theme_cowplot() +
labs(title=paste("Accelerometer Features: \n Average Accuracy Across",perm_time,"Permutations"),
x = "Mobility Footprint Individual Identification Accuracy", y = "Count") +
#geom_density(alpha=.2) +
theme(plot.title = element_text(hjust = 0.5))
ggplotly(p)
perm_acc_acc_subj = unlist(perm_acc_acc_subj)
Warning messages:
1: In readChar(file, size, TRUE) : truncating string with embedded nuls
2: In readChar(file, size, TRUE) : truncating string with embedded nuls
perm_subj = sapply(subject_seq, function(subj) sum(perm_acc_acc_subj[which(names(perm_acc_acc_subj) == subj)])/1000)
subj_df <- data.frame(x=names(subj_seq))
subj_df$y = acc_acc_subj
subj_df$y_perm = perm_subj
subj_df = subj_df[order(subj_df$y),]
p_subj_cor_perm = ggplot(subj_df, aes(x = reorder(x, y), y = value)) +
geom_point(aes(y = y, col = "subject data")) +
geom_point(aes(y = y_perm, col = "permutation")) +
theme_cowplot() +
labs(title = paste("Accelerometer \n Subject Level Accuracy Across",perm_time,"permutations"),
x = "Subjects", y = "Individual identification accuracy") +
theme(axis.text.x = element_text(angle = 45, hjust = 1, size = 8), plot.title = element_text(hjust = 0.5))
ggplotly(p_subj_cor_perm)
df_accgps_time = data.frame(GPS = gps_acc_time, Accelerometer = acc_acc_time, `GPS and Acceleromter` = acc_time_cb_accgps)
df_accgps_time_long = gather(df_accgps_time, feature, accuracy, 1:3, factor_key=TRUE)
mu = ddply(df_accgps_time_long, "feature", summarise, grp.mean=mean(accuracy))
p_accgps_feature = ggplot(df_accgps_time_long, aes(x=accuracy,color = feature, fill = feature)) +
geom_density(size = 1, alpha = 0) +
#geom_histogram(aes(y=..density..), alpha=0.2,
# position="identity") +
geom_vline(data=mu, aes(xintercept=grp.mean, color=feature),
linetype="dashed") +
labs(y = "Density", x = "Individual Identitication Accuracy") +
theme_cowplot() +
theme(legend.position="top")
p_accgps_feature

8. Data quantity vs. quality associations
gps_days = gps_df_clean2 %>% group_by(IID) %>% dplyr::tally(name = "gps_days")
Warning messages:
1: In readChar(file, size, TRUE) : truncating string with embedded nuls
2: In readChar(file, size, TRUE) : truncating string with embedded nuls
3: In readChar(file, size, TRUE) : truncating string with embedded nuls
acc_days = subj_acc_data_clean %>% group_by(IID) %>% dplyr::tally(name = "acc_days")
data_quant_plots = list()
data_quant_plots$gps = conf_scatter_plot(gps_days, gps_acc_subj, "gps_days")
data_quant_plots$acc = conf_scatter_plot(acc_days, acc_acc_subj, "acc_days")
Reduce(`+`,data_quant_plots)

gps_quality = gps_df_clean2 %>% group_by(IID) %>% dplyr::summarize(MinsMissing = mean(MinsMissing,na.rm=T))
#acc_quality = sapply(subj_list,get_data_mean)
#acc_quality$IID = names(acc_data_quality)
#acc_quality$datapoints = as.numeric(value(unlist(acc_data_quality)[1:41]))
data_qual_plots = list()
data_qual_plots$gps = conf_scatter_plot(gps_quality, gps_acc_subj, "MinsMissing")
data_qual_plots$acc = conf_scatter_plot(acc_quality, acc_acc_subj, "datapoints")
Reduce(`+`,data_qual_plots)

9. Developmental effects and sex differences
ids = read.xlsx(file.path(project_path,"data/clinical_data/subjecttracker_4.xlsx"))[1:41,c(1,3)]
demo_tem = read.csv(file.path(project_path,"data/clinical_data/self_report_itemwise.csv"), colClasses = c("NULL",NA,"NULL","NULL",NA,NA,rep("NULL",363)))
demo_beiwe = inner_join(ids,demo_tem, by = c("BBLID" = "bblid"))
acc_subj_df = data.frame(beiweID = names(acc_subj), gps = gps_acc_subj, acc = acc_acc_subj, accgps = acc_subj_cb_accgps)
acc_demo_df = inner_join(acc_subj_df,demo_beiwe, by = "beiweID")
acc_demo_df = inner_join(acc_demo_df,gps_days, by = c("beiweID" = "IID"))
acc_demo_df = inner_join(acc_demo_df,acc_days, by = c("beiweID" = "IID"))
acc_demo_df$admin_sex = as.factor(acc_demo_df$admin_sex)
agesex_gps_fit = gam(gps ~ s(admin_age) + admin_sex + gps_days, data = acc_demo_df, method = "REML")
p_gps = list()
p_gps$sex = visreg(agesex_gps_fit, "admin_sex", gg = T, line=list(col="#3576b5",size = 0.5, alpha = 0.25),
points=list(size=2, pch=19), fill= list(fill=c("#b3d3f2"), alpha = 0.25)) +
xlab("Sex") + ylab("Individual Footprint Distinctiveness \n (GPS)") + theme_cowplot()
p_gps$age = visreg(agesex_gps_fit, "admin_age", gg = T, line=list(col="#3576b5",size = 0.5, alpha = 0.25),
points=list(size=2, pch=19), fill= list(fill=c("#b3d3f2"), alpha = 1)) +
xlab("Age") + ylab("Individual Footprint Distinctiveness \n (GPS)") + theme_cowplot()
Reduce(`+`,p_gps)

agesex_acc_fit = gam(acc ~ s(admin_age) + admin_sex + acc_days , data = acc_demo_df, method = "REML")
p_acc = list()
p_acc$age = visreg(agesex_acc_fit, "admin_age", gg = T, line=list(col="#3576b5",size = 0.5, alpha = 0.25),
points=list(size=2, pch=19), fill= list(fill=c("#b3d3f2"), alpha = 0.25)) +
xlab("Age") + ylab("Individual Footprint Distinctiveness \n (Accel)") + theme_cowplot()
p_acc$sex = visreg(agesex_acc_fit, "admin_sex", gg = T, line=list(col="#3576b5",size = 0.5, alpha = 0.25),
points=list(size=2, pch=19), fill= list(fill=c("#b3d3f2"), alpha = 1)) +
xlab("Sex") + ylab("Individual Footprint Distinctiveness \n (Accel)") + theme_cowplot()
Reduce(`+`,p_acc)

10. Mood and sleep variability
11. Functional connectivity
LS0tCnRpdGxlOiAiTW9iaWxlIEZvb3RwcmludGluZyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQojIyMgMS4gU2V0dXAgRW52aXJvbm1lbnQgCgpgYGB7ciBsb2FkIHBhY2thZ2VzLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPVRSVUV9CnJlcXVpcmUoZ2dwbG90MikKcmVxdWlyZShzdW1tYXJ5dG9vbHMpCnJlcXVpcmUoY293cGxvdCkKcmVxdWlyZShjYXJldCkKcmVxdWlyZShjb3JycGxvdCkKcmVxdWlyZShSQ29sb3JCcmV3ZXIpCnJlcXVpcmUodmVtYmVkcikKcmVxdWlyZShSbWlzYykKcmVxdWlyZSh2YXJpYW4pCnJlcXVpcmUocGF0Y2h3b3JrKQpyZXF1aXJlKHBsb3RseSkKcmVxdWlyZShNZXRyaWNzKQpyZXF1aXJlKGRwbHlyKQpyZXF1aXJlKGdncHVicikKcmVxdWlyZShtb3NhaWMpCnJlcXVpcmUob3Blbnhsc3gpCnJlcXVpcmUodmlzcmVnKQpyZXF1aXJlKGZhY3RvZXh0cmEpCnJlcXVpcmUocnN0YXRpeCkKcmVxdWlyZShncmlkRXh0cmEpCnJlcXVpcmUoY29sb3JzcGFjZSkKcmVxdWlyZShncmlkKQpyZXF1aXJlKGRhdGEudGFibGUpCnJlcXVpcmUocHN5Y2gpCnNvdXJjZSgnfi9Eb2N1bWVudHMvR2l0SHViL1NtYXJ0cGhvbmVTZW5zb3JQaXBlbGluZS9FeHRyYS9wbG90dGluZ19mdW5jdGlvbnMuUicpCmBgYAoKYGBge3IgZGVmaW5lIHBhdGhzfQpwcm9qZWN0X3BhdGggPSAifi9Eb2N1bWVudHMveGlhX2dwcy8iCmRhdGFfcGF0aCA9IGZpbGUucGF0aChwcm9qZWN0X3BhdGgsImJlaXdlX291dHB1dF8wNDMwMjAiKQpncHNfZGZfcGF0aCA9IGZpbGUucGF0aChkYXRhX3BhdGgsIlByb2Nlc3NlZF9EYXRhL0dyb3VwL2ZlYXR1cmVfbWF0cml4LnR4dCIpCmBgYAoKCiMjIyAyLlByZXBhcmUgR1BTIGRhdGEgCmBgYHtyIHJlYWRfZ3BzfQpncHNfZGYgPSByZWFkLnRhYmxlKGdwc19kZl9wYXRoLGhlYWRlciA9IFQsIGRlYyA9ICIsIilbLGMoMSwyLDk3OjExMSldCmdwc19kZlssMzoxN10gPSBhcHBseShncHNfZGZbLDM6MTddLDIsYXMubnVtZXJpYykKYGBgCgpgYGB7ciBleGNsdWRlIEdQUyBkYXRhLCBmaWcud2lkdGg9MTAsIGZpZy5oZWlnaHQ9NH0KIyBsb29wIHRocm91Z2ggZWFjaCBzdWJqIHRvIHJlbW92ZSAxc3QgYW5kIGxhc3QgZGF5cyBvZiBncHMgZGF0YQoJZ3BzX2RmX2NsZWFuID0gZGF0YS5mcmFtZSgpICNpbml0aWF0ZSBhIGRmCglmb3IgKHN1YmogaW4gdW5pcXVlKGdwc19kZiRJSUQpKXsgI2xvb3AgdGhyb3VnaCBlYWNoIHN1YmoKCSAgZ3BzX2RmX3N1YmogPC0gc3Vic2V0KGdwc19kZiwgSUlEID09IHN1YmopICNnZXQgZ3BzX2RmIHBlciBzdWJqZWN0CgkgIGdwc19kZl9zdWJqIDwtIGdwc19kZl9zdWJqWzI6KGRpbShncHNfZGZfc3ViailbMV0tMSksXSAjcmVtb3ZlIHRoZSAxc3QgYW5kIGxhc3QgZGF5cwoJICBncHNfZGZfY2xlYW4gPC0gcmJpbmQoZ3BzX2RmX2NsZWFuLGdwc19kZl9zdWJqKSAjY29tYmluZSBhbGwgc3VianMKCX0KCgkjIGV4Y2x1ZGUgZGF5cyB3aXRoIHRvbyBtdWNoIGV4Y2Vzc2l2ZW5lc3MKCXNlbnNpdGl2aXR5X2N1dG9mZiA9IDE0NDAgIyB0aGlzIGNvbnRyb2xzIHRoZSBjdXRvZmYgdGhyZXNob2xkCglncHNfZGZfY2xlYW4yID0gc3Vic2V0KGdwc19kZl9jbGVhbiwgTWluc01pc3NpbmcgPCBzZW5zaXRpdml0eV9jdXRvZmYpCmBgYAogICAKYGBge3IgUGFydGl0aW9uIEdQUyBkYXRhfQpzZXQuc2VlZCg1MTApCnBhcnRfdGltZXMgPSAxMDAwCnN1Ympfc2VxID0gbWFrZV9zdWJqX3NlcShncHNfZGZfY2xlYW4yLCBwYXJ0X3RpbWVzKQpgYGAKCmBgYHtyIGV4YW1wbGVfY29yX2ZpZywgZmlnLndpZHRoPTMsIGZpZy53aWR0aD0zLCBmaWcuYWxpZ249ImNlbnRlciJ9CiMgYW4gZXhhbXBsZSBvZiBzdWJqIDEsIGFuZCBmaXJzdCBoYWxmCmV4YW1wbGVfZGF0YSA9IGdwc19kZl9jbGVhbjJbc3Vial9zZXEkYDE2eHY2a28xYCRSZXNhbXBsZTAwMDEsMzoxN10KZ3BzX2NvciA9IHJxdWVyeS5jb3JtYXQoZXhhbXBsZV9kYXRhLCB0eXBlID0gImZ1bGwiKQpgYGAKCmBgYHtyIGNyZWF0ZSBmZWF0dXJlIG1hdHJpeCBmb3IgZXZlcnlvbmUsIHdhcm5pbmc9RkFMU0V9CgpncHNfY2xlYW4yX2ZlYXR1cmUgPSBtYWtlX2ZlYXR1cmVfbWF0cml4KGdwc19kZl9jbGVhbjIsIHN1Ympfc2VxLCAzOjE3ICkKc3ViamVjdF9zZXEgPSBuYW1lcyhncHNfY2xlYW4yX2ZlYXR1cmUkc3Vial9tYXRfMSkKYGBgCgpgYGB7ciB2aXN1YWxpemF0aW9uIG9mIGZlYXR1cmUgY29ycmVsYXRpb25zIGFjcm9zcyBzdWJqZWN0c30KZ3BzX3dpZGVfbWF0cml4ID0gZGF0YS5mcmFtZSgpCnN1YmpfZGF5cyA9IGdwc19kZl9jbGVhbjIgJT4lIGdyb3VwX2J5KElJRCkgJT4lIGRwbHlyOjp0YWxseShuYW1lID0gIkRheXMgQ29sbGVjdGVkIikKZm9yIChzdWJqIGluIGFycmFuZ2Uoc3Vial9kYXlzLGBEYXlzIENvbGxlY3RlZGApJElJRCl7CiAgI2lmICgoc3ViaiAlaW4lIHN1YmpfZGF5cyRJSURbd2hpY2goc3Vial9kYXlzJGBEYXlzIENvbGxlY3RlZGA8PTEwKV0pID09IFQpIHsKICAgIGZvciAocGFydCBpbiAxOjUpewogICAgICBoYWxmXzEgPSBncHNfY2xlYW4yX2ZlYXR1cmUkc3Vial9tYXRfMVtbc3Vial1dW1twYXJ0XV0kY29yCiAgICAgIGhhbGZfMiA9IGdwc19jbGVhbjJfZmVhdHVyZSRzdWJqX21hdF8yW1tzdWJqXV1bW3BhcnRdXSRjb3IKICAgICAgaGFsZl8xX2hhbGZfMiA9IGMoaGFsZl8xLGhhbGZfMikKICAgICAgZ3BzX3dpZGVfbWF0cml4ID0gcmJpbmQoZ3BzX3dpZGVfbWF0cml4LGhhbGZfMSkKICAgICAgZ3BzX3dpZGVfbWF0cml4ID0gcmJpbmQoZ3BzX3dpZGVfbWF0cml4LGhhbGZfMikKICAgICAgfQogICAgI30KfQoKZ3BzX3dpZGVfbWF0cml4ID0gdChncHNfd2lkZV9tYXRyaXgpCmdwc19jb3JwbG90ID0gcnF1ZXJ5LmNvcm1hdChncHNfd2lkZV9tYXRyaXgsIHR5cGUgPSAiZnVsbCIsZ3JhcGg9RkFMU0UpCmdwc19jb3JwbG90JHN1YmogPSBhcnJhbmdlKHN1YmpfZGF5cyxgRGF5cyBDb2xsZWN0ZWRgKSRJSUQKCmxldmVscGxvdChncHNfY29ycGxvdCRyLHNjYWxlcz1saXN0KGRyYXc9RkFMU0UpLGNvbC5yZWdpb25zID0gcmV2KHJhaW5ib3coMTAwMCkpWy1jKDE6MjApXSwgcmVnaW9uID1ULCB5bGFiLnJpZ2h0ID0gIlBlYXJzb24gY29ycmVsYXRpb24iLCBtYWluPWxpc3QobGFiZWw9J0dQUyBGZWF0dXJlIFNpbWlsYXJpdHknKSx4bGFiPSIiLHlsYWI9IiIpCmBgYAoKIyMjIDMuIFByZXBhcmUgYWNjZWxlcm9tZXRlciBkYXRhCmBgYHtyIG9yZ2FuaXppbmcgYWNjZWxlcm9tZXRlciBkYXRhfQpzdWJqX2xpc3QgPSB1bmlxdWUoZ3BzX2RmJElJRCkKc3Vial9hY2NfZGF0YV9kaW0gPSBkaW0ocmJpbmRsaXN0KGxhcHBseShzdWJqX2xpc3QsIGZ1bmN0aW9uKHN1YmopIHtzdWJqX2RhdGEgPSAgcmVhZFJEUyhmaWxlLnBhdGgoZGF0YV9wYXRoLCJSZXN1bHRzL0dyb3VwL2FjY2VsZXJvbWV0ZXIiLHN1YmosImFjY2VsZXJvbWV0ZXJfZnQucmRzIikpOyBzdWJqX2RhdGFbLGMoMjo4LDExKV19KSkpCgpzdWJqX2FjY19kYXRhX2NsZWFuID0gYXMuZGF0YS5mcmFtZShyYmluZGxpc3QobGFwcGx5KHN1YmpfbGlzdCwgZnVuY3Rpb24oc3ViaikgeyBzdWJqX2RhdGEgPSAgcmVhZFJEUyhmaWxlLnBhdGgoZGF0YV9wYXRoLCJSZXN1bHRzL0dyb3VwL2FjY2VsZXJvbWV0ZXIiLHN1YmosImFjY2VsZXJvbWV0ZXJfZnQucmRzIikpOyBzdWJqX2RhdGFbMjooZGltKHN1YmpfZGF0YSlbMV0tMSksYygyOjgsMTEpXX0pKSkgI2Fsc28gcmVtb3ZlcyAxc3QgYW5kIGxhc3QgZGF5CmBgYAoKYGBge3IgZXhhbXBsZSBvZiB0aGUgY292IG9mIGFjY2VsZXJvbWV0ZXIsZmlnLndpZHRoPTMsIGZpZy53aWR0aD0zLGZpZy5hbGlnbj0iY2VudGVyIn0KZXhhbXBsZV9hY2NfZGF0YSA9IHN1YmpfYWNjX2RhdGFfY2xlYW5bc3Vial9zZXEkYDE2eHY2a28xYCRSZXNhbXBsZTAwMDEsMTo3XQphY2NfY29yID0gcnF1ZXJ5LmNvcm1hdChleGFtcGxlX2FjY19kYXRhLCB0eXBlID0gImZ1bGwiKQpgYGAKCmBgYHtyIGNhbGMgYWNjIGZlYXR1cmVzfQpzdWJqX2FjY19kYXRhX2NsZWFuJElJRCA9IHN1YmpfYWNjX2RhdGFfY2xlYW4kc3ViamVjdApzZXQuc2VlZCg1MTApCmFjY19zdWJqX3NlcSA9IG1ha2Vfc3Vial9zZXEoc3Vial9hY2NfZGF0YV9jbGVhbiwgcGFydF90aW1lcykKYWNjX2NsZWFuX2ZlYXR1cmUgPSBtYWtlX2ZlYXR1cmVfbWF0cml4KHN1YmpfYWNjX2RhdGFfY2xlYW4sIGFjY19zdWJqX3NlcSwgIGMoMTo3KSApCgpgYGAKCmBgYHtyIHBsb3QgYWNjIHN1YmplY3Qgc2ltaWxhcml0eSBtYXRyaXh9CmFjY193aWRlX21hdHJpeCA9IGRhdGEuZnJhbWUoKQpzdWJqX2FjY19kYXlzID0gc3Vial9hY2NfZGF0YV9jbGVhbiAlPiUgZ3JvdXBfYnkoSUlEKSAlPiUgZHBseXI6OnRhbGx5KG5hbWUgPSAiYWNjX2RheXMiKQpmb3IgKHN1YmogaW4gYXJyYW5nZShzdWJqX2FjY19kYXlzLGBhY2NfZGF5c2ApJElJRCl7CiAgICBmb3IgKHBhcnQgaW4gMTo1KXsKICAgICAgaGFsZl8xID0gYWNjX2NsZWFuX2ZlYXR1cmUkc3Vial9tYXRfMVtbc3Vial1dW1twYXJ0XV0kY29yCiAgICAgIGhhbGZfMiA9IGFjY19jbGVhbl9mZWF0dXJlJHN1YmpfbWF0XzJbW3N1YmpdXVtbcGFydF1dJGNvcgogICAgICBoYWxmXzFfaGFsZl8yID0gYyhoYWxmXzEsaGFsZl8yKQogICAgICBhY2Nfd2lkZV9tYXRyaXggPSByYmluZChhY2Nfd2lkZV9tYXRyaXgsaGFsZl8xKQogICAgICBhY2Nfd2lkZV9tYXRyaXggPSByYmluZChhY2Nfd2lkZV9tYXRyaXgsaGFsZl8yKQogICAgICB9Cn0KCmFjY193aWRlX21hdHJpeCA9IHQoYWNjX3dpZGVfbWF0cml4KQphY2NfY29ycGxvdCA9IHJxdWVyeS5jb3JtYXQoYWNjX3dpZGVfbWF0cml4LCB0eXBlID0gImZ1bGwiLGdyYXBoPUZBTFNFKQphY2NfY29ycGxvdCRzdWJqID0gYXJyYW5nZShzdWJqX2FjY19kYXlzLGBhY2NfZGF5c2ApJElJRAoKbGV2ZWxwbG90KGFjY19jb3JwbG90JHIsc2NhbGVzPWxpc3QoZHJhdz1GQUxTRSksY29sLnJlZ2lvbnMgPSByZXYocmFpbmJvdygxMDAwKSlbLWMoMToyMCldLCByZWdpb24gPVQsIHlsYWIucmlnaHQgPSAiUGVhcnNvbiBjb3JyZWxhdGlvbiIsIG1haW49bGlzdChsYWJlbD0nQWNjIEZlYXR1cmUgU2ltaWxhcml0eScpLHhsYWI9IiIseWxhYj0iIikKYGBgCgojIyMgNC4gTWVyZ2UgR1BTIGFuZCBhY2NlbGVyb21ldGVyIGRhdGEKYGBge3IgY29tYmluZSBncHMgKyBhY2N9Cmdwc19hY2NfY29tYmluZWRfZmVhdCA9IGxpc3QoKQpmb3IgKHN1YmogaW4gc3Vial9saXN0KXsKICBmb3IgKHRpbWUgaW4gMTpwYXJ0X3RpbWVzKXsKICAgIGdwc19mZWF0MSA9IGdwc19jbGVhbjJfZmVhdHVyZSRzdWJqX21hdF8xW1tzdWJqXV1bW3RpbWVdXSRjb3IKICAgIGFjY19mZWF0MSA9IGFjY19jbGVhbl9mZWF0dXJlJHN1YmpfbWF0XzFbW3N1YmpdXVtbdGltZV1dJGNvcgogICAgCiAgICBncHNfZmVhdDIgPSBncHNfY2xlYW4yX2ZlYXR1cmUkc3Vial9tYXRfMltbc3Vial1dW1t0aW1lXV0kY29yCiAgICBhY2NfZmVhdDIgPSBhY2NfY2xlYW5fZmVhdHVyZSRzdWJqX21hdF8yW1tzdWJqXV1bW3RpbWVdXSRjb3IKCiAgICBncHNfYWNjX2NvbWJpbmVkX2ZlYXQkc3Vial9tYXRfMVtbc3Vial1dW1t0aW1lXV0gPSBjKGdwc19mZWF0MSwgYWNjX2ZlYXQxKQogICAgZ3BzX2FjY19jb21iaW5lZF9mZWF0JHN1YmpfbWF0XzJbW3N1YmpdXVtbdGltZV1dID0gYyhncHNfZmVhdDIsIGFjY19mZWF0MikKICB9Cn0KYGBgCgoKIyMjIDUuIEdQUyBhbmQgYWNjZWxlcm9tZXRlciBiYXNlZCBJbmRpdmlkdWFsIElkZW50aWZpY2F0aW9uCmBgYHtyIG1hdGNoIHdpdGggY29tYmluZWQgZmVhdHVyZXN9Cm1hdGNoX2NvbWJpbmVkX2dwc19hY2NmZWF0ID0gY2FsY19tYXRjaF92ZWN0b3IoZ3BzX2FjY19jb21iaW5lZF9mZWF0JHN1YmpfbWF0XzEsIGdwc19hY2NfY29tYmluZWRfZmVhdCRzdWJqX21hdF8yLCAiY29yIikKYWNjX3RpbWVfY2JfYWNjZ3BzICA9IGNhbGNfYWNjX3RpbWUobWF0Y2hfY29tYmluZWRfZ3BzX2FjY2ZlYXQsICJtYXgiKQphY2Nfc3Vial9jYl9hY2NncHMgID0gY2FsY19hY2Nfc3ViaihtYXRjaF9jb21iaW5lZF9ncHNfYWNjZmVhdCwgIm1heCIpCmBgYAoKYGBge3IgLCBmaWcuYWxpZ249ImNlbnRlciIsIGZpZy5oZWlnaHQ9NSwgZmlnLndpZHRoPTV9CnAgPSBoaXN0X2NoeChhY2NfdGltZV9jYl9hY2NncHMsIGJpbnMgPSAxNCwgdGl0bGUgPSBwYXN0ZSgiSW5kaXZpZHVhbCBJZGVudGlmaWNhaXRvbiBBY2N1cmFjeSBcbiAoR1BTKyBBY2NlbCkiKSwgeGF4aXMgPSAiUHJlZGljdGlvbiBBY2N1cmFjeSIsIHlheGlzID0gIkNvdW50IikKZ2dwbG90bHkocCkKYGBgCgoKCmBgYHtyIGFjYytncHMgcGVybX0KcGVybV90aW1lID0gMTAKZ3BzX2RmX3Blcm0gPSBncHNfZGZfY2xlYW4yCmFjY19kZl9wZXJtID0gc3Vial9hY2NfZGF0YV9jbGVhbgoKcGVybV9hY2NfZ3BzX3RpbWUgPSBsaXN0KCkKcGVybV9hY2NfZ3BzX3N1YmogPSBsaXN0KCkKCmZvciAoaSBpbiAxOnBlcm1fdGltZSkgewogIHBlcm1fcGFydF90aW1lcyA9IDEKICBwcmludChwYXN0ZSgicHJvY2Vzc2luZyAuLi4iLCBpLCIuLi4iKSkKICBncHNfZGZfcGVybSRJSUQgPSBzYW1wbGUoZ3BzX2RmX3Blcm0kSUlEKQogIGFjY19kZl9wZXJtJElJRCA9IHNhbXBsZShhY2NfZGZfcGVybSRJSUQpCiAgCiAgcGVybV9zdWJqX3NlcSA9IG1ha2Vfc3Vial9zZXEoZ3BzX2RmX3Blcm0scGFydF90aW1lcyA9IHBlcm1fcGFydF90aW1lcykKICBwZXJtX2FjY19zdWJqX3NlcSA9IG1ha2Vfc3Vial9zZXEoYWNjX2RmX3Blcm0scGFydF90aW1lcyA9IHBlcm1fcGFydF90aW1lcykKICAKICBwZXJtX2dwc19jb3IgPSBtYWtlX2ZlYXR1cmVfbWF0cml4KGdwc19kZl9wZXJtLHBlcm1fc3Vial9zZXEsMzoxNykKICBwZXJtX2FjY19jb3IgPSBtYWtlX2ZlYXR1cmVfbWF0cml4KGFjY19kZl9wZXJtLHBlcm1fYWNjX3N1Ympfc2VxLDE6NykKICAKICBzdWJqX21hdF8xID0gbGlzdCgpCiAgc3Vial9tYXRfMiA9IGxpc3QoKQogIAogICAgZm9yIChzdWJqIGluIHN1YmpfbGlzdCl7CiAgICAgICAgc3Vial9tYXRfMVtbc3Vial1dJFJlc2FtcGxlMSA9IGFzLm51bWVyaWMoYyhwZXJtX2dwc19jb3Ikc3Vial9tYXRfMVtbc3Vial1dW1sxXV0kY29yLCBwZXJtX2FjY19jb3Ikc3Vial9tYXRfMVtbc3Vial1dW1sxXV0kY29yKSkKICAgICAgICBzdWJqX21hdF8yW1tzdWJqXV0kUmVzYW1wbGUxID0gYXMubnVtZXJpYyhjKHBlcm1fZ3BzX2NvciRzdWJqX21hdF8yW1tzdWJqXV1bWzFdXSRjb3IsIHBlcm1fYWNjX2NvciRzdWJqX21hdF8yW1tzdWJqXV1bWzFdXSRjb3IpKQogICAgfQogIHBlcm1fZ3BzX2FjY19tYXRzID0gbGlzdChzdWJqX21hdF8xID0gc3Vial9tYXRfMSwgc3Vial9tYXRfMiA9IHN1YmpfbWF0XzIpCiAgCiAgcGVybV9tYXRjaCA9IGNhbGNfbWF0Y2hfdmVjdG9yKHBlcm1fZ3BzX2FjY19tYXRzJHN1YmpfbWF0XzEscGVybV9ncHNfYWNjX21hdHMkc3Vial9tYXRfMiwgImNvciIpCiAgcGVybV9hY2NfZ3BzX3RpbWVbW2ldXSA9IGNhbGNfYWNjX3RpbWUocGVybV9tYXRjaCwgIm1heCIpCiAgcGVybV9hY2NfZ3BzX3N1YmpbW2ldXSA9IGNhbGNfYWNjX3N1YmoocGVybV9tYXRjaCwgIm1heCIpCn0KCgpwZXJtX2FjY19ncHNfdGltZSA9IHVubGlzdChwZXJtX2FjY19ncHNfdGltZSkKcGVybV9hY2NfZ3BzX3N1YmogPSB1bmxpc3QocGVybV9hY2NfZ3BzX3N1YmopCgpgYGAKCmBgYHtyIGdwc19hY2NlbCBwZXJtdXRhdGlvbn0KZGYgPSBkYXRhLmZyYW1lKHZhbCA9IHBlcm1fYWNjX2dwc190aW1lKQpwID0gZ2dwbG90KGRmLCBhZXMoeD12YWwpKSArIAogICAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDcsIGZpbGwgPSAiIzlFQ0FFMSIsIHNpemUgPSAyKSArIAogICAgdGhlbWVfY293cGxvdCgpICsKICAgIGxhYnModGl0bGU9cGFzdGUoIkdQUytBY2NlbDogXG4iLHBhcnRfdGltZXMsIlBlcm11dGF0aW9ucyIpLAogICAgICAgICB4ICA9ICJJbmRpdmlkdWFsIElkZW50aWZpY2FpdG9uIEFjY3VyYWN5IiwgeSA9ICJDb3VudCIpICsgCiAgI2dlb21fZGVuc2l0eShhbHBoYT0uMikgKwogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCmdncGxvdGx5KHApCmBgYApgYGB7ciBwbG90IHN1YmogYW5hbHlzaXMgd2l0aCBwZXJtLCBmaWcud2lkdGg9OCwgZmlnLmhlaWdodD00fQpwZXJtX3N1YmogPSBzYXBwbHkoc3ViamVjdF9zZXEsIGZ1bmN0aW9uKHN1YmopIHN1bShwZXJtX2FjY19ncHNfc3Vialt3aGljaChuYW1lcyhwZXJtX2FjY19ncHNfc3ViaikgPT0gc3ViaildKS8xMDAwKQoKc3Vial9kZiA8LSBkYXRhLmZyYW1lKHg9bmFtZXMoc3Vial9zZXEpKQpzdWJqX2RmJHkgPSBhY2Nfc3Vial9jYl9hY2NncHMKc3Vial9kZiR5X3Blcm0gPSBwZXJtX3N1YmoKc3Vial9kZiA9IHN1YmpfZGZbb3JkZXIoc3Vial9kZiR5KSxdCnBfc3Vial9jb3JfcGVybSA9IGdncGxvdChzdWJqX2RmLCBhZXMoeCA9IHJlb3JkZXIoeCwgeSksIHkgPSB2YWx1ZSkpICsgCiAgZ2VvbV9wb2ludChhZXMoeSA9IHkpLCBjb2xvciA9ICIjRjY5Mjc0Iiwgc2l6ZSA9IDIpICsgCiAgZ2VvbV9wb2ludChhZXMoeSA9IHlfcGVybSksIGNvbG9yID0gIiM5RUNBRTEiLCBzaXplID0yICkgKwogIHRoZW1lX2Nvd3Bsb3QoKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiR1BTK0FjY2VsIFxuIFN1YmplY3QgTGV2ZWwgQWNjdXJhY3kgQWNyb3NzIixwYXJ0X3RpbWVzLCJEYXRhIFBhcnRpdGlvbnMiKSwgCiAgICAgICB4ID0gIlN1YmplY3RzIiwgeSA9ICJJbmRpdmlkdWFsIElkZW50aWZpY2F0aW9uIEFjY3VyYWN5IikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDgpLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKZ2dwbG90bHkocF9zdWJqX2Nvcl9wZXJtKQpgYGAKCiMjIyA2LiBHUFMgb25seSBiYXNlZCBJbmRpdmlkdWFsIElkZW50aWZpY2F0aW9uCmBgYHtyIGdwcyBJRH0KZ3BzX21hdGNoX2NvciA9IGNhbGNfbWF0Y2hfY29yKGdwc19jbGVhbjJfZmVhdHVyZSRzdWJqX21hdF8xLGdwc19jbGVhbjJfZmVhdHVyZSRzdWJqX21hdF8yKQpncHNfYWNjX3RpbWUgPSBjYWxjX2FjY190aW1lKGdwc19tYXRjaF9jb3IsICJtYXgiKQpncHNfYWNjX3N1YmogPSBjYWxjX2FjY19zdWJqKGdwc19tYXRjaF9jb3IpCgpncHNfZGZfcGVybSA9IGdwc19kZl9jbGVhbjIKcGVybV90aW1lID0gMTAwMApwZXJtX2FjY190aW1lID0gbGlzdCgpCnBlcm1fYWNjX3N1YmogPSBsaXN0KCkKZm9yIChpIGluIDE6cGVybV90aW1lKSB7CiAgcGVybV9wYXJ0X3RpbWVzID0gMQogIHByaW50KHBhc3RlKCJwcm9jZXNzaW5nIC4uLiIsIGksIi4uLiIpKQogIGdwc19kZl9wZXJtJElJRCA9IHNhbXBsZShncHNfZGZfcGVybSRJSUQpCiAgcGVybV9zdWJqX3NlcSA9IG1ha2Vfc3Vial9zZXEoZ3BzX2RmX3Blcm0sIHBhcnRfdGltZXMgPSBwZXJtX3BhcnRfdGltZXMpCiAgcGVybV9ncHMgPSBtYWtlX2ZlYXR1cmVfbWF0cml4KGdwc19kZl9wZXJtLHBlcm1fc3Vial9zZXEsMzoxNykKICBwZXJtX21hdF8xID0gcGVybV9ncHMkc3Vial9tYXRfMQogIHBlcm1fbWF0XzIgPSBwZXJtX2dwcyRzdWJqX21hdF8yCiAgcGVybV9tYXRjaF9jb3IgPSBjYWxjX21hdGNoX2NvcihwZXJtX21hdF8xLHBlcm1fbWF0XzIpCiAgcGVybV9hY2NfdGltZVtbaV1dID0gY2FsY19hY2NfdGltZShwZXJtX21hdGNoX2NvcikKICBwZXJtX2FjY19zdWJqW1tpXV0gPSBjYWxjX2FjY19zdWJqKHBlcm1fbWF0Y2hfY29yKQp9CmBgYAoKYGBge3IgZ3BzIHBsb3RzIDF9CnBfdGltZV9jb3IgPSBoaXN0X2NoeChhY2NfdGltZSwgYmlucyA9IDE3LCB0aXRsZSA9IHBhc3RlKCJHUFM6IFxuIEluZGl2aWR1YWwgaWRlbnRpZmljYXRpb24gYWNjdXJhY3kiKSwgeGF4aXMgPSAiSW5kaXZpZHVhbCBpZGVudGlmaWNhdGlvbiBhY2N1cmFjeSIsIHlheGlzID0gIkNvdW50IikKZ2dwbG90bHkocF90aW1lX2NvcikKYGBgCgpgYGB7ciBncHMgcGxvdHMgMn0KI3Blcm1fYWNjX3RpbWVfYWxsID0gdW5saXN0KHBlcm1fYWNjX3RpbWUpCnFfdGltZV9jb3IgPSBoaXN0X2NoeChwZXJtX2FjY190aW1lX2FsbCwgYmlucyA9IDcsIHRpdGxlID0gcGFzdGUoIkdQUyBhY2N1cmFjeSBhY3Jvc3MiLGxlbmd0aChwZXJtX2FjY190aW1lX2FsbCksIlBlcm11dGF0aW9ucyIpLCB4YXhpcyA9ICJJbmRpdmlkdWFsIElkZW50aWZpY2FpdG9uIEFjY3VyYWN5IiwgeWF4aXMgPSAiQ291bnQiKQpnZ3Bsb3RseShxX3RpbWVfY29yKQpgYGAKCmBgYHtyIGdwcyBwbG90cyAzfQpwZXJtX2FjY19zdWJqID0gdW5saXN0KHBlcm1fYWNjX3N1YmopCnBlcm1fc3ViaiA9IHNhcHBseShzdWJqZWN0X3NlcSwgZnVuY3Rpb24oc3Viaikgc3VtKHBlcm1fYWNjX3N1Ympbd2hpY2gobmFtZXMocGVybV9hY2Nfc3ViaikgPT0gc3ViaildKS8xMDAwKQoKc3Vial9kZiA8LSBkYXRhLmZyYW1lKHg9bmFtZXMoc3Vial9zZXEpKQpzdWJqX2RmJHkgPSBncHNfYWNjX3N1YmoKc3Vial9kZiR5X3Blcm0gPSBwZXJtX3N1YmoKc3Vial9kZiA9IHN1YmpfZGZbb3JkZXIoc3Vial9kZiR5KSxdCnBfc3Vial9jb3JfcGVybSA9IGdncGxvdChzdWJqX2RmLCBhZXMoeCA9IHJlb3JkZXIoeCwgeSksIHkgPSB2YWx1ZSkpICsgCiAgZ2VvbV9wb2ludChhZXMoeSA9IHksIGNvbCA9ICJzdWJqZWN0IGRhdGEiKSkgKyAKICBnZW9tX3BvaW50KGFlcyh5ID0geV9wZXJtLCBjb2wgPSAicGVybXV0YXRpb24iKSkgKwogIHRoZW1lX2Nvd3Bsb3QoKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiR1BTIFxuIFN1YmplY3QgTGV2ZWwgQWNjdXJhY3kgQWNyb3NzIixwZXJtX3RpbWUsInBlcm11dGF0aW9ucyIpLCAKICAgICAgIHggPSAiU3ViamVjdHMiLCB5ID0gIkluZGl2aWR1YWwgaWRlbnRpZmljYXRpb24gYWNjdXJhY3kiKSArCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxLCBzaXplID0gOCksIHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQpnZ3Bsb3RseShwX3N1YmpfY29yX3Blcm0pCmBgYAoKIyMjIDcuIEFjY2VsZXJvbWV0ZXIgb25seSBiYXNlZCBJbmRpdmlkdWFsIElkZW50aWZpY2F0aW9uIApgYGB7ciBtYXRjaCBvbiBhY2MgZmVhdHVyZXN9CmFjY19tYXRjaF9jb3IgPSBjYWxjX21hdGNoX2NvcihhY2NfY2xlYW5fZmVhdHVyZSRzdWJqX21hdF8xLGFjY19jbGVhbl9mZWF0dXJlJHN1YmpfbWF0XzIpCmFjY19hY2NfdGltZSA9IGNhbGNfYWNjX3RpbWUoYWNjX21hdGNoX2NvciwgIm1heCIpCmFjY19hY2Nfc3ViaiA9IGNhbGNfYWNjX3N1YmooYWNjX21hdGNoX2NvcikKYGBgCgpgYGB7ciBhY2MgcGVybX0KYWNjX2RmX3Blcm0gPSBzdWJqX2FjY19kYXRhX2NsZWFuCnBlcm1fdGltZSA9IDEwMDAKcGVybV9hY2NfYWNjX3RpbWUgPSBsaXN0KCkKcGVybV9hY2NfYWNjX3N1YmogPSBsaXN0KCkKZm9yIChpIGluIDE6cGVybV90aW1lKSB7CiAgcGVybV9wYXJ0X3RpbWVzID0gMQogIHByaW50KHBhc3RlKCJwcm9jZXNzaW5nIC4uLiIsIGksIi4uLiIpKQogIGFjY19kZl9wZXJtJElJRCA9IHNhbXBsZShhY2NfZGZfcGVybSRJSUQpCiAgcGVybV9zdWJqX3NlcSA9IG1ha2Vfc3Vial9zZXEoYWNjX2RmX3Blcm0sIHBhcnRfdGltZXMgPSBwZXJtX3BhcnRfdGltZXMpCiAgcGVybV9hY2MgPSBtYWtlX2ZlYXR1cmVfbWF0cml4KGFjY19kZl9wZXJtLHBlcm1fc3Vial9zZXEsMTo3KQogIHBlcm1fbWF0XzEgPSBwZXJtX2FjYyRzdWJqX21hdF8xCiAgcGVybV9tYXRfMiA9IHBlcm1fYWNjJHN1YmpfbWF0XzIKICBwZXJtX21hdGNoX2NvciA9IGNhbGNfbWF0Y2hfY29yKHBlcm1fbWF0XzEscGVybV9tYXRfMikKICBwZXJtX2FjY19hY2NfdGltZVtbaV1dID0gY2FsY19hY2NfdGltZShwZXJtX21hdGNoX2NvcikKICBwZXJtX2FjY19hY2Nfc3VialtbaV1dID0gY2FsY19hY2Nfc3ViaihwZXJtX21hdGNoX2NvcikKfQpgYGAKCmBgYHtyIGFjYyBwbG90cyAxfQpkZiA9IGRhdGEuZnJhbWUodmFsID0gYWNjX2FjY190aW1lKQpwID0gZ2dwbG90KGRmLCBhZXMoeD12YWwpKSArIAogICAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDE1LCBmaWxsID0gIiNGNjkyNzQiLCBzaXplID0gMikgKyAKICAgIHRoZW1lX2Nvd3Bsb3QoKSArCiAgICBsYWJzKHRpdGxlPXBhc3RlKCJBY2NlbGVyb21ldGVyIEZlYXR1cmVzOiBcbiBBdmVyYWdlIEFjY3VyYWN5IEFjcm9zcyIscGFydF90aW1lcywiRGF0YSBQYXJ0aXRpb25zIiksCiAgICAgICAgIHggID0gIk1vYmlsaXR5IEZvb3RwcmludCBJbmRpdmlkdWFsIElkZW50aWZpY2F0aW9uIEFjY3VyYWN5IiwgeSA9ICJDb3VudCIpICsgCiAgI2dlb21fZGVuc2l0eShhbHBoYT0uMikgKwogICAgdGhlbWUocGxvdC50aXRsZSA9IGVsZW1lbnRfdGV4dChoanVzdCA9IDAuNSkpCmdncGxvdGx5KHApCmBgYApgYGB7ciBhY2MgcGxvdHMgMn0KZGYgPSBkYXRhLmZyYW1lKHZhbCA9IHBlcm1fYWNjX2FjY190aW1lKQpwID0gZ2dwbG90KGRmLCBhZXMoeD12YWwpKSArIAogICAgZ2VvbV9oaXN0b2dyYW0oYmlucyA9IDUsIGZpbGwgPSAiIzlFQ0FFMSIsIHNpemUgPSAyKSArIAogICAgdGhlbWVfY293cGxvdCgpICsKICAgIGxhYnModGl0bGU9cGFzdGUoIkFjY2VsZXJvbWV0ZXIgRmVhdHVyZXM6IFxuIEF2ZXJhZ2UgQWNjdXJhY3kgQWNyb3NzIixwZXJtX3RpbWUsIlBlcm11dGF0aW9ucyIpLAogICAgICAgICB4ICA9ICJNb2JpbGl0eSBGb290cHJpbnQgSW5kaXZpZHVhbCBJZGVudGlmaWNhdGlvbiBBY2N1cmFjeSIsIHkgPSAiQ291bnQiKSArIAogICNnZW9tX2RlbnNpdHkoYWxwaGE9LjIpICsKICAgIHRoZW1lKHBsb3QudGl0bGUgPSBlbGVtZW50X3RleHQoaGp1c3QgPSAwLjUpKQpnZ3Bsb3RseShwKQpgYGAKYGBge3IgYWNjIHBsb3RzIDN9CnBlcm1fYWNjX2FjY19zdWJqID0gdW5saXN0KHBlcm1fYWNjX2FjY19zdWJqKQpwZXJtX3N1YmogPSBzYXBwbHkoc3ViamVjdF9zZXEsIGZ1bmN0aW9uKHN1YmopIHN1bShwZXJtX2FjY19hY2Nfc3Vialt3aGljaChuYW1lcyhwZXJtX2FjY19hY2Nfc3ViaikgPT0gc3ViaildKS8xMDAwKQoKc3Vial9kZiA8LSBkYXRhLmZyYW1lKHg9bmFtZXMoc3Vial9zZXEpKQpzdWJqX2RmJHkgPSBhY2NfYWNjX3N1YmoKc3Vial9kZiR5X3Blcm0gPSBwZXJtX3N1YmoKc3Vial9kZiA9IHN1YmpfZGZbb3JkZXIoc3Vial9kZiR5KSxdCnBfc3Vial9jb3JfcGVybSA9IGdncGxvdChzdWJqX2RmLCBhZXMoeCA9IHJlb3JkZXIoeCwgeSksIHkgPSB2YWx1ZSkpICsgCiAgZ2VvbV9wb2ludChhZXMoeSA9IHksIGNvbCA9ICJzdWJqZWN0IGRhdGEiKSkgKyAKICBnZW9tX3BvaW50KGFlcyh5ID0geV9wZXJtLCBjb2wgPSAicGVybXV0YXRpb24iKSkgKwogIHRoZW1lX2Nvd3Bsb3QoKSArIAogIGxhYnModGl0bGUgPSBwYXN0ZSgiQWNjZWxlcm9tZXRlciBcbiBTdWJqZWN0IExldmVsIEFjY3VyYWN5IEFjcm9zcyIscGVybV90aW1lLCJwZXJtdXRhdGlvbnMiKSwgCiAgICAgICB4ID0gIlN1YmplY3RzIiwgeSA9ICJJbmRpdmlkdWFsIGlkZW50aWZpY2F0aW9uIGFjY3VyYWN5IikgKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSwgc2l6ZSA9IDgpLCBwbG90LnRpdGxlID0gZWxlbWVudF90ZXh0KGhqdXN0ID0gMC41KSkKZ2dwbG90bHkocF9zdWJqX2Nvcl9wZXJtKQpgYGAKCmBgYHtyIGdzcCB2IGFjYyB2cyBncHMrYWNjfQpkZl9hY2NncHNfdGltZSA9IGRhdGEuZnJhbWUoR1BTID0gZ3BzX2FjY190aW1lLCBBY2NlbGVyb21ldGVyID0gYWNjX2FjY190aW1lLCBgR1BTIGFuZCBBY2NlbGVyb210ZXJgID0gYWNjX3RpbWVfY2JfYWNjZ3BzKQpkZl9hY2NncHNfdGltZV9sb25nID0gZ2F0aGVyKGRmX2FjY2dwc190aW1lLCBmZWF0dXJlLCBhY2N1cmFjeSwgMTozLCBmYWN0b3Jfa2V5PVRSVUUpCm11ID0gZGRwbHkoZGZfYWNjZ3BzX3RpbWVfbG9uZywgImZlYXR1cmUiLCBzdW1tYXJpc2UsIGdycC5tZWFuPW1lYW4oYWNjdXJhY3kpKQpwX2FjY2dwc19mZWF0dXJlID0gZ2dwbG90KGRmX2FjY2dwc190aW1lX2xvbmcsIGFlcyh4PWFjY3VyYWN5LGNvbG9yID0gZmVhdHVyZSwgZmlsbCA9IGZlYXR1cmUpKSArIAogICAgZ2VvbV9kZW5zaXR5KHNpemUgPSAxLCBhbHBoYSA9IDApICsgCiAgICAjZ2VvbV9oaXN0b2dyYW0oYWVzKHk9Li5kZW5zaXR5Li4pLCBhbHBoYT0wLjIsIAogICAgIyAgICAgICAgICAgIHBvc2l0aW9uPSJpZGVudGl0eSIpICsgCiAgICBnZW9tX3ZsaW5lKGRhdGE9bXUsIGFlcyh4aW50ZXJjZXB0PWdycC5tZWFuLCBjb2xvcj1mZWF0dXJlKSwKICAgICAgICAgICAgIGxpbmV0eXBlPSJkYXNoZWQiKSArCiAgICBsYWJzKHkgPSAiRGVuc2l0eSIsIHggPSAiSW5kaXZpZHVhbCBJZGVudGl0aWNhdGlvbiBBY2N1cmFjeSIpICsgCiAgICB0aGVtZV9jb3dwbG90KCkgKwogICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSJ0b3AiKQpwX2FjY2dwc19mZWF0dXJlCmBgYAoKCgojIyMgOC4gRGF0YSBxdWFudGl0eSB2cy4gcXVhbGl0eSBhc3NvY2lhdGlvbnMKYGBge3IgZGF0YSBxdWFudGl0eX0KZ3BzX2RheXMgPSBncHNfZGZfY2xlYW4yICU+JSBncm91cF9ieShJSUQpICU+JSBkcGx5cjo6dGFsbHkobmFtZSA9ICJncHNfZGF5cyIpCmFjY19kYXlzID0gc3Vial9hY2NfZGF0YV9jbGVhbiAlPiUgZ3JvdXBfYnkoSUlEKSAlPiUgZHBseXI6OnRhbGx5KG5hbWUgPSAiYWNjX2RheXMiKQpkYXRhX3F1YW50X3Bsb3RzID0gbGlzdCgpCmRhdGFfcXVhbnRfcGxvdHMkZ3BzID0gY29uZl9zY2F0dGVyX3Bsb3QoZ3BzX2RheXMsIGdwc19hY2Nfc3ViaiwgImdwc19kYXlzIikKZGF0YV9xdWFudF9wbG90cyRhY2MgPSBjb25mX3NjYXR0ZXJfcGxvdChhY2NfZGF5cywgYWNjX2FjY19zdWJqLCAiYWNjX2RheXMiKQpSZWR1Y2UoYCtgLGRhdGFfcXVhbnRfcGxvdHMpCmBgYAoKCmBgYHtyIGRhdGEgcXVhbGl0eX0KZ3BzX3F1YWxpdHkgPSBncHNfZGZfY2xlYW4yICU+JSBncm91cF9ieShJSUQpICU+JSBkcGx5cjo6c3VtbWFyaXplKE1pbnNNaXNzaW5nID0gbWVhbihNaW5zTWlzc2luZyxuYS5ybT1UKSkKI2FjY19xdWFsaXR5ID0gc2FwcGx5KHN1YmpfbGlzdCxnZXRfZGF0YV9tZWFuKQojYWNjX3F1YWxpdHkkSUlEID0gbmFtZXMoYWNjX2RhdGFfcXVhbGl0eSkKI2FjY19xdWFsaXR5JGRhdGFwb2ludHMgPSBhcy5udW1lcmljKHZhbHVlKHVubGlzdChhY2NfZGF0YV9xdWFsaXR5KVsxOjQxXSkpCgpkYXRhX3F1YWxfcGxvdHMgPSBsaXN0KCkKZGF0YV9xdWFsX3Bsb3RzJGdwcyA9IGNvbmZfc2NhdHRlcl9wbG90KGdwc19xdWFsaXR5LCBncHNfYWNjX3N1YmosICJNaW5zTWlzc2luZyIpCmRhdGFfcXVhbF9wbG90cyRhY2MgPSBjb25mX3NjYXR0ZXJfcGxvdChhY2NfcXVhbGl0eSwgYWNjX2FjY19zdWJqLCAiZGF0YXBvaW50cyIpCgpSZWR1Y2UoYCtgLGRhdGFfcXVhbF9wbG90cykKYGBgCgojIyMgOS4gRGV2ZWxvcG1lbnRhbCBlZmZlY3RzIGFuZCBzZXggZGlmZmVyZW5jZXMKYGBge3IgY3VyYXRlIGRlbW9ncmFwaGljIGRhdGF9CmlkcyA9IHJlYWQueGxzeChmaWxlLnBhdGgocHJvamVjdF9wYXRoLCJkYXRhL2NsaW5pY2FsX2RhdGEvc3ViamVjdHRyYWNrZXJfNC54bHN4IikpWzE6NDEsYygxLDMpXQpkZW1vX3RlbSA9IHJlYWQuY3N2KGZpbGUucGF0aChwcm9qZWN0X3BhdGgsImRhdGEvY2xpbmljYWxfZGF0YS9zZWxmX3JlcG9ydF9pdGVtd2lzZS5jc3YiKSwgY29sQ2xhc3NlcyA9IGMoIk5VTEwiLE5BLCJOVUxMIiwiTlVMTCIsTkEsTkEscmVwKCJOVUxMIiwzNjMpKSkKCmRlbW9fYmVpd2UgPSBpbm5lcl9qb2luKGlkcyxkZW1vX3RlbSwgYnkgPSBjKCJCQkxJRCIgPSAiYmJsaWQiKSkKYWNjX3N1YmpfZGYgPSBkYXRhLmZyYW1lKGJlaXdlSUQgPSBuYW1lcyhhY2Nfc3ViaiksIGdwcyA9IGdwc19hY2Nfc3ViaiwgYWNjID0gYWNjX2FjY19zdWJqLCBhY2NncHMgPSBhY2Nfc3Vial9jYl9hY2NncHMpCmFjY19kZW1vX2RmID0gaW5uZXJfam9pbihhY2Nfc3Vial9kZixkZW1vX2JlaXdlLCBieSA9ICJiZWl3ZUlEIikKYWNjX2RlbW9fZGYgPSBpbm5lcl9qb2luKGFjY19kZW1vX2RmLGdwc19kYXlzLCBieSA9IGMoImJlaXdlSUQiID0gIklJRCIpKQphY2NfZGVtb19kZiA9IGlubmVyX2pvaW4oYWNjX2RlbW9fZGYsYWNjX2RheXMsIGJ5ID0gYygiYmVpd2VJRCIgPSAiSUlEIikpCmFjY19kZW1vX2RmJGFkbWluX3NleCA9IGFzLmZhY3RvcihhY2NfZGVtb19kZiRhZG1pbl9zZXgpCmBgYAoKYGBge3IgZ3BzIGFnZSBhbmQgc2V4fQphZ2VzZXhfZ3BzX2ZpdCA9IGdhbShncHMgfiBzKGFkbWluX2FnZSkgKyBhZG1pbl9zZXggKyBncHNfZGF5cywgZGF0YSA9IGFjY19kZW1vX2RmLCBtZXRob2QgPSAiUkVNTCIpCgpwX2dwcyA9IGxpc3QoKQoKcF9ncHMkYWdlID0gdmlzcmVnKGFnZXNleF9ncHNfZml0LCAiYWRtaW5fYWdlIiwgZ2cgPSBULCBsaW5lPWxpc3QoY29sPSIjMzU3NmI1IixzaXplID0gMC41LCBhbHBoYSA9IDAuMjUpLCAKICAgICAgIHBvaW50cz1saXN0KHNpemU9MiwgcGNoPTE5KSwgZmlsbD0gbGlzdChmaWxsPWMoIiNiM2QzZjIiKSwgYWxwaGEgPSAxKSkgKyAKICB4bGFiKCJBZ2UiKSArIHlsYWIoIkluZGl2aWR1YWwgRm9vdHByaW50IERpc3RpbmN0aXZlbmVzcyBcbiAoR1BTKSIpICsgIHRoZW1lX2Nvd3Bsb3QoKQoKcF9ncHMkc2V4ID0gdmlzcmVnKGFnZXNleF9ncHNfZml0LCAiYWRtaW5fc2V4IiwgZ2cgPSBULCBsaW5lPWxpc3QoY29sPSIjMzU3NmI1IixzaXplID0gMC41LCBhbHBoYSA9IDAuMjUpLCAKICAgICAgIHBvaW50cz1saXN0KHNpemU9MiwgcGNoPTE5KSwgZmlsbD0gbGlzdChmaWxsPWMoIiNiM2QzZjIiKSwgYWxwaGEgPSAwLjI1KSkgKyAKICB4bGFiKCJTZXgiKSArIHlsYWIoIkluZGl2aWR1YWwgRm9vdHByaW50IERpc3RpbmN0aXZlbmVzcyBcbiAoR1BTKSIpICsgIHRoZW1lX2Nvd3Bsb3QoKQoKUmVkdWNlKGArYCxwX2dwcykKYGBgCgpgYGB7ciBhY2MgYWdlIGFuZCBzZXh9CmFnZXNleF9hY2NfZml0ID0gZ2FtKGFjYyB+IHMoYWRtaW5fYWdlKSArIGFkbWluX3NleCArIGFjY19kYXlzICwgZGF0YSA9IGFjY19kZW1vX2RmLCBtZXRob2QgPSAiUkVNTCIpCgpwX2FjYyA9IGxpc3QoKQoKcF9hY2MkYWdlID0gdmlzcmVnKGFnZXNleF9hY2NfZml0LCAiYWRtaW5fYWdlIiwgZ2cgPSBULCBsaW5lPWxpc3QoY29sPSIjMzU3NmI1IixzaXplID0gMC41LCBhbHBoYSA9IDAuMjUpLCAKICAgICAgIHBvaW50cz1saXN0KHNpemU9MiwgcGNoPTE5KSwgZmlsbD0gbGlzdChmaWxsPWMoIiNiM2QzZjIiKSwgYWxwaGEgPSAwLjI1KSkgKyAKICB4bGFiKCJBZ2UiKSArIHlsYWIoIkluZGl2aWR1YWwgRm9vdHByaW50IERpc3RpbmN0aXZlbmVzcyBcbiAoQWNjZWwpIikgKyAgdGhlbWVfY293cGxvdCgpCgpwX2FjYyRzZXggPSB2aXNyZWcoYWdlc2V4X2FjY19maXQsICJhZG1pbl9zZXgiLCBnZyA9IFQsIGxpbmU9bGlzdChjb2w9IiMzNTc2YjUiLHNpemUgPSAwLjUsIGFscGhhID0gMC4yNSksIAogICAgICAgcG9pbnRzPWxpc3Qoc2l6ZT0yLCBwY2g9MTkpLCBmaWxsPSBsaXN0KGZpbGw9YygiI2IzZDNmMiIpLCBhbHBoYSA9IDEpKSArIAogIHhsYWIoIlNleCIpICsgeWxhYigiSW5kaXZpZHVhbCBGb290cHJpbnQgRGlzdGluY3RpdmVuZXNzIFxuIChBY2NlbCkiKSArICB0aGVtZV9jb3dwbG90KCkKClJlZHVjZShgK2AscF9hY2MpCmBgYAoKCiMjIyAxMC4gTW9vZCBhbmQgc2xlZXAgdmFyaWFiaWxpdHkKCiMjIyAxMS4gRnVuY3Rpb25hbCBjb25uZWN0aXZpdHkK